home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / actionrp / nhplusx.bin / nhplusx / nhplusX / X11 / winstat.c < prev    next >
C/C++ Source or Header  |  1995-09-10  |  27KB  |  968 lines

  1. /*    SCCS Id: @(#)winstat.c    3.1    93/02/04    */
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * Status window routines.  This file supports both the "traditional"
  7.  * tty status display and a "fancy" status display.  A tty status is
  8.  * made if a popup window is requested, otherewise a fancy status is
  9.  * made.  This code assumes that only one fancy status will ever be made.
  10.  * Currently, only one status window (of any type) is _ever_ made.
  11.  */
  12.  
  13. #ifndef SYSV
  14. #define PRESERVE_NO_SYSV    /* X11 include files may define SYSV */
  15. #endif
  16.  
  17. #include <X11/Intrinsic.h>
  18. #include <X11/StringDefs.h>
  19. #include <X11/Shell.h>
  20. #include <X11/Xaw/AsciiText.h>
  21. #include <X11/Xaw/Cardinals.h>
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/Label.h>
  24. #include <X11/Xatom.h>
  25.  
  26. #ifdef PRESERVE_NO_SYSV
  27. # ifdef SYSV
  28. #  undef SYSV
  29. # endif
  30. # undef PRESERVE_NO_SYSV
  31. #endif
  32.  
  33. #include "hack.h"
  34. #include "winX.h"
  35.  
  36. extern const char *hu_stat[]; /* from eat.c */
  37. extern const char *enc_stat[]; /* from botl.c */
  38.  
  39. static void FDECL(update_fancy_status, (struct xwindow *));
  40. static Widget FDECL(create_fancy_status, (Widget,Widget));
  41.  
  42. void
  43. create_status_window(wp, create_popup, parent)
  44.     struct xwindow *wp;            /* window pointer */
  45.     boolean create_popup;
  46.     Widget parent;
  47. {
  48.     XFontStruct *fs;
  49.     Arg args[8];
  50.     Cardinal num_args;
  51.     Position top_margin, bottom_margin, left_margin, right_margin;
  52.  
  53.     wp->type = NHW_STATUS;
  54.  
  55.     if (!create_popup) {
  56.     /*
  57.      * If we are not creating a popup, then we must be the "main" status
  58.      * window.
  59.      */
  60.     if (!parent)
  61.         panic("create_status_window: no parent for fancy status");
  62.     wp->status_information = 0;
  63.     wp->w = create_fancy_status(parent, (Widget) 0);
  64.     return;
  65.     }
  66.  
  67.     wp->status_information =
  68.         (struct status_info_t *) alloc(sizeof(struct status_info_t));
  69.  
  70.     init_text_buffer(&wp->status_information->text);
  71.  
  72.     num_args = 0;
  73.     XtSetArg(args[num_args], XtNallowShellResize, False); num_args++;
  74.     XtSetArg(args[num_args], XtNinput, False);            num_args++;
  75.  
  76.     wp->popup = parent = XtCreatePopupShell("status_popup",
  77.                     topLevelShellWidgetClass,
  78.                     toplevel, args, num_args);
  79.     /*
  80.      * If we're here, then this is an auxiliary status window.  If we're
  81.      * cancelled via a delete window message, we should just pop down.
  82.      */
  83.  
  84.     num_args = 0;
  85.     XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++;
  86.     XtSetArg(args[num_args], XtNscrollHorizontal,
  87.                     XawtextScrollWhenNeeded);    num_args++;
  88.     XtSetArg(args[num_args], XtNscrollVertical,
  89.                     XawtextScrollWhenNeeded);    num_args++;
  90.  
  91.     wp->w = XtCreateManagedWidget(
  92.         "status",        /* name */
  93.         asciiTextWidgetClass,
  94.         parent,            /* parent widget */
  95.         args,            /* set some values */
  96.         num_args);        /* number of values to set */
  97.  
  98.     /*
  99.      * Adjust the height and width of the message window so that it
  100.      * is two lines high and COLNO of the widest characters wide.
  101.      */
  102.  
  103.     /* Get the font and margin information. */
  104.     num_args = 0;
  105.     XtSetArg(args[num_args], XtNfont,          &fs);           num_args++;
  106.     XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
  107.     XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
  108.     XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
  109.     XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
  110.     XtGetValues(wp->w, args, num_args);
  111.  
  112.     /* font height is ascent + descent */
  113.     wp->pixel_height = 2 * (fs->ascent + fs->descent) +
  114.                         top_margin + bottom_margin;
  115.     wp->pixel_width  = COLNO * fs->max_bounds.width +
  116.                         left_margin + right_margin;
  117.  
  118.     /* Set the new width and height. */
  119.     num_args = 0;
  120.     XtSetArg(args[num_args], XtNwidth,  wp->pixel_width);  num_args++;
  121.     XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
  122.     XtSetValues(wp->w, args, num_args);
  123. }
  124.  
  125. void
  126. destroy_status_window(wp)
  127.     struct xwindow *wp;
  128. {
  129.     /* If status_information is defined, then it a "text" status window. */
  130.     if (wp->status_information) {
  131.     nh_XtPopdown(wp->popup);
  132.     XtDestroyWidget(wp->popup);
  133.     free((char *) wp->status_information);
  134.     }
  135.     wp->type = NHW_NONE;
  136. }
  137.  
  138.  
  139. /*
  140.  * This assumes several things:
  141.  *    + Status has only 2 lines
  142.  *    + That both lines are updated in succession in line order.
  143.  *    + We didn't set stringInPlace on the widget.
  144.  */
  145. void
  146. adjust_status(wp, str)
  147.     struct xwindow *wp;
  148.     const char *str;
  149. {
  150.     Arg args[2];
  151.     Cardinal num_args;
  152.  
  153.     if (!wp->status_information) {
  154.     update_fancy_status(wp);
  155.     return;
  156.     }
  157.  
  158.     if (wp->cursy == 0) {
  159.     clear_text_buffer(&wp->status_information->text);
  160.     append_text_buffer(&wp->status_information->text, str, FALSE);
  161.     return;
  162.     }
  163.     append_text_buffer(&wp->status_information->text, str, FALSE);
  164.  
  165.     /* Set new buffer as text. */
  166.     num_args = 0;
  167.     XtSetArg(args[num_args], XtNstring, wp->status_information->text.text);
  168.                                     num_args++;
  169.     XtSetValues(wp->w, args, num_args);
  170. }
  171.  
  172.  
  173. /* Fancy Status -------------------------------------------------------------*/
  174. static Widget init_info_form();
  175. static Widget init_column();
  176. static void set_widths();
  177. static void get_widths();
  178. static void create_widget();
  179. static const char *width_string();
  180. static void hilight_label();
  181. static void update_val();
  182.  
  183. static int hilight_time = 1;    /* number of turns to hilight a changed value */
  184.  
  185. struct X_status_value {
  186.     char    *name;        /* text name */
  187.     int     type;        /* status type */
  188.     Widget  w;            /* widget of name/value pair */
  189.     int     last_value;        /* value displayed */
  190.     int        turn_count;        /* last time the value changed */
  191.     boolean set;        /* if hilighed */
  192.     boolean after_init;        /* don't hilight on first change (init) */
  193. };
  194.  
  195. /* valid type values */
  196. #define SV_VALUE 0    /* displays a label:value pair */
  197. #define SV_LABEL 1    /* displays a changable label */
  198. #define SV_NAME  2    /* displays an unchangeable name */
  199.  
  200. /*
  201.  * Form entry storage indices.
  202.  */
  203. #define F_STR        0
  204. #define F_DEX        1
  205. #define F_CON        2
  206. #define F_INT        3
  207. #define F_WIS        4
  208. #define F_CHA        5
  209.  
  210. #define F_NAME      6
  211. #define F_DLEVEL    7
  212. #define F_GOLD      8
  213. #define F_HP        9
  214. #define F_MAXHP       10
  215. #define F_POWER    11
  216. #define F_MAXPOWER 12
  217. #define F_AC       13
  218. #define F_LEVEL    14
  219. #define F_EXP      15
  220. #define F_ALIGN       16
  221. #define F_TIME     17
  222. #define F_SCORE       18
  223.  
  224. #define F_HUNGER   19
  225. #define F_CONFUSED 20
  226. #define F_SICK       21
  227. #define F_BLIND       22
  228. #define F_STUNNED  23
  229. #define F_HALLU    24
  230. #define F_ENCUMBER 25
  231.  
  232. #define NUM_STATS  26
  233.  
  234. /*
  235.  * Notes:
  236.  * + Alignment needs a different init value, because -1 is an alignment.
  237.  * + Armor Class is an schar, so 256 is out of range.
  238.  * + Blank value is 0 and should never change.
  239.  */
  240. static struct X_status_value shown_stats[NUM_STATS] = {
  241.     { "Strength",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 0*/
  242.     { "Dexterity",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  243.     { "Constitution",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  244.     { "Intelligence",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  245.     { "Wisdom",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  246.     { "Charisma",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /* 5*/
  247.  
  248.     { "",        SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */
  249.     { "",        SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */
  250.     { "Gold",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  251.     { "Hit Points",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  252.     { "Max HP",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*10*/
  253.     { "Power",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  254.     { "Max Power",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  255.     { "Armor Class",    SV_VALUE, (Widget) 0,256, 0, FALSE, FALSE },
  256.     { "Level",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  257.     { "Experience",    SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },    /*15*/
  258.     { "Alignment",    SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE },
  259.     { "Time",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  260.     { "Score",        SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE },
  261.  
  262.     { "",        SV_NAME,  (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/
  263.     { "Confused",    SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },    /*20*/
  264.     { "Sick",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  265.     { "Blind",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  266.     { "Stunned",    SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  267.     { "Hallucinating",    SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE },
  268.     { "",        SV_NAME,  (Widget) 0,  0, 0, FALSE, TRUE }, /*encumbr*/
  269. };
  270.  
  271.  
  272. /*
  273.  * Set all widget values to a null string.  This is used after all spacings
  274.  * have been calculated so that when the window is popped up we don't get all
  275.  * kinds of funny values being displayed.
  276.  */
  277. void
  278. null_out_status()
  279. {
  280.     int i;
  281.     struct X_status_value *sv;
  282.     Arg args[1];
  283.  
  284.     for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
  285.     switch (sv->type) {
  286.         case SV_VALUE:
  287.         set_value(sv->w, "");
  288.         break;
  289.  
  290.         case SV_LABEL:
  291.         case SV_NAME:
  292.         XtSetArg(args[0], XtNlabel, "");
  293.         XtSetValues(sv->w, args, ONE);
  294.         break;
  295.  
  296.         default:
  297.         impossible("null_out_status: unknown type %d\n", sv->type);
  298.         break;
  299.     }
  300.     }
  301. }
  302.  
  303. /* This is almost an exact duplicate of hilight_value() */
  304. static void
  305. hilight_label(w)
  306.     Widget w;    /* label widget */
  307. {
  308.     Arg args[2];
  309.     Pixel fg, bg;
  310.  
  311.     XtSetArg(args[0], XtNforeground, &fg);
  312.     XtSetArg(args[1], XtNbackground, &bg);
  313.     XtGetValues(w, args, TWO);
  314.  
  315.     XtSetArg(args[0], XtNforeground, bg);
  316.     XtSetArg(args[1], XtNbackground, fg);
  317.     XtSetValues(w, args, TWO);
  318. }
  319.  
  320.  
  321. static void
  322. update_val(attr_rec, new_value)
  323.     struct X_status_value *attr_rec;
  324.     long new_value;
  325. {
  326.     char buf[BUFSZ];
  327.     Arg args[4];
  328.  
  329.     if (attr_rec->type == SV_LABEL) {
  330.  
  331.     if (attr_rec == &shown_stats[F_NAME]) {
  332.  
  333.         Strcpy(buf, plname);
  334.         if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
  335.         Strcat(buf, " the ");
  336. #ifdef POLYSELF
  337.         if (u.mtimedone) {
  338.         char mname[BUFSZ];
  339.         int k = 0;
  340.  
  341.         Strcpy(mname, mons[u.umonnum].mname);
  342.         while(mname[k] != 0) {
  343.             if ((k == 0 || (k > 0 && mname[k-1] == ' ')) &&
  344.                     'a' <= mname[k] && mname[k] <= 'z')
  345.                 mname[k] += 'A' - 'a';
  346.             k++;
  347.         }
  348.         Strcat(buf, mname);
  349.         } else
  350. #endif
  351.         Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female));
  352.  
  353.     } else if (attr_rec == &shown_stats[F_DLEVEL]) {
  354.         if (In_endgame(&u.uz)) {
  355.         Strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane":"End Game"));
  356.         } else {
  357.         Strcpy(buf, dungeons[u.uz.dnum].dname);
  358.         Sprintf(eos(buf), ", level %d", depth(&u.uz));
  359.         }
  360.     } else {
  361.         impossible("update_val: unknown label type \"%s\"",
  362.                             attr_rec->name);
  363.         return;
  364.     }
  365.  
  366.     if (strcmp(buf, attr_rec->name) == 0) return;    /* same */
  367.  
  368.     /* Set the label. */
  369.     Strcpy(attr_rec->name, buf);
  370.     XtSetArg(args[0], XtNlabel, buf);
  371.     XtSetValues(attr_rec->w, args, ONE);
  372.  
  373.     } else if (attr_rec->type == SV_NAME) {
  374.  
  375.     if (attr_rec->last_value == new_value) return;    /* no change */
  376.  
  377.     attr_rec->last_value = new_value;
  378.  
  379.     /* special cases: hunger and encumbrance */
  380.     if (attr_rec == &shown_stats[F_HUNGER]) {
  381.         XtSetArg(args[0], XtNlabel, hu_stat[new_value]);
  382.     } else if (attr_rec == &shown_stats[F_ENCUMBER]) {
  383.         XtSetArg(args[0], XtNlabel, enc_stat[new_value]);
  384.     } else if (new_value) {
  385.         XtSetArg(args[0], XtNlabel, attr_rec->name);
  386.     } else {
  387.         XtSetArg(args[0], XtNlabel, "");
  388.     }
  389.     XtSetValues(attr_rec->w, args, ONE);
  390.  
  391.     } else {    /* a value pair */
  392.     boolean force_update = FALSE;
  393.  
  394.     /* special case: time can be enabled & disabled */
  395.     if (attr_rec == &shown_stats[F_TIME]) {
  396.         static boolean flagtime = TRUE;
  397.  
  398.         if(flags.time && !flagtime) {
  399.         set_name(attr_rec->w, shown_stats[F_TIME].name);
  400.         force_update = TRUE;
  401.         flagtime = flags.time;
  402.         } else if(!flags.time && flagtime) {
  403.         set_name(attr_rec->w, "");
  404.         set_value(attr_rec->w, "");
  405.         flagtime = flags.time;
  406.         }
  407.         if(!flagtime) return;
  408.     }
  409.  
  410.     /* special case: exp can be enabled & disabled */
  411.     else if (attr_rec == &shown_stats[F_EXP]) {
  412.         static boolean flagexp = TRUE;
  413. #ifdef EXP_ON_BOTL
  414.  
  415.         if (flags.showexp && !flagexp) {
  416.         set_name(attr_rec->w, shown_stats[F_EXP].name);
  417.         force_update = TRUE;
  418.         flagexp = flags.showexp;
  419.         } else if(!flags.showexp && flagexp) {
  420.         set_name(attr_rec->w, "");
  421.         set_value(attr_rec->w, "");
  422.         flagexp = flags.showexp;
  423.         }
  424.         if (!flagexp) return;
  425. #else
  426.         if (flagexp) {
  427.         set_name(attr_rec->w, "");
  428.         set_value(attr_rec->w, "");
  429.         flagexp = FALSE;
  430.         }
  431.         return;    /* don't show it at all */
  432. #endif
  433.     }
  434.  
  435.     /* special case: score can be enabled & disabled */
  436.     else if (attr_rec == &shown_stats[F_SCORE]) {
  437.         static boolean flagscore = TRUE;
  438. #ifdef SCORE_ON_BOTL
  439.  
  440.         if(flags.showscore && !flagscore) {
  441.         set_name(attr_rec->w, shown_stats[F_SCORE].name);
  442.         force_update = TRUE;
  443.         flagscore = flags.showscore;
  444.         } else if(!flags.showscore && flagscore) {
  445.         set_name(attr_rec->w, "");
  446.         set_value(attr_rec->w, "");
  447.         flagscore = flags.showscore;
  448.         }
  449.         if(!flagscore) return;
  450. #else
  451.         if (flagscore) {
  452.         set_name(attr_rec->w, "");
  453.         set_value(attr_rec->w, "");
  454.         flagscore = FALSE;
  455.         }
  456.         return;
  457. #endif
  458.     }
  459.  
  460. #ifdef POLYSELF
  461.     /* special case: when polymorphed, show "HD", disable exp */
  462.     else if (attr_rec == &shown_stats[F_LEVEL]) {
  463.         static boolean lev_was_poly = FALSE;
  464.  
  465.         if (u.mtimedone && !lev_was_poly) {
  466.         force_update = TRUE;
  467.         set_name(attr_rec->w, "HD");
  468.         lev_was_poly = TRUE;
  469.         } else if (!u.mtimedone && lev_was_poly) {
  470.         force_update = TRUE;
  471.         set_name(attr_rec->w, shown_stats[F_LEVEL].name);
  472.         lev_was_poly = FALSE;
  473.         }
  474.     } else if (attr_rec == &shown_stats[F_EXP]) {
  475.         static boolean exp_was_poly = FALSE;
  476.  
  477.         if (u.mtimedone && !exp_was_poly) {
  478.         force_update = TRUE;
  479.         set_name(attr_rec->w, "");
  480.         set_value(attr_rec->w, "");
  481.         exp_was_poly = TRUE;
  482.         } else if (!u.mtimedone && exp_was_poly) {
  483.         force_update = TRUE;
  484.         set_name(attr_rec->w, shown_stats[F_EXP].name);
  485.         exp_was_poly = FALSE;
  486.         }
  487.         if (u.mtimedone) return;    /* no display for exp when poly */
  488.     }
  489. #endif
  490.  
  491.     if (attr_rec->last_value == new_value && !force_update)    /* same */
  492.         return;
  493.  
  494.     attr_rec->last_value = new_value;
  495.  
  496.     /* Special cases: strength, alignment and "clear". */
  497.     if (attr_rec == &shown_stats[F_STR]) {
  498.         if(new_value > 18) {
  499.         if (new_value > 118)
  500.             Sprintf(buf,"%d", new_value-100);
  501.         else if(new_value < 118)
  502.             Sprintf(buf, "18/%02d", new_value-18);
  503.         else
  504.             Strcpy(buf, "18/**");
  505.         } else {
  506.         Sprintf(buf, "%d", new_value);
  507.         }
  508.     } else if (attr_rec == &shown_stats[F_ALIGN]) {
  509.  
  510.         Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" :
  511.             (new_value == A_NEUTRAL) ? "Neutral" :
  512.                            "Lawful"  );
  513.     } else {
  514.         Sprintf(buf, "%d", new_value);
  515.     }
  516.     set_value(attr_rec->w, buf);
  517.     }
  518.  
  519.     /*
  520.      * Now hilight the changed information.  Names, time and score don't
  521.      * hilight.  If first time, don't hilight.  If already lit, don't do
  522.      * it again.
  523.      */
  524.     if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) {
  525.     if (attr_rec->after_init) {
  526.         if(!attr_rec->set) {
  527.         if (attr_rec->type == SV_LABEL)
  528.             hilight_label(attr_rec->w);
  529.         else
  530.             hilight_value(attr_rec->w);
  531.         attr_rec->set = TRUE;
  532.         }
  533.         attr_rec->turn_count = 0;
  534.     } else {
  535.         attr_rec->after_init = TRUE;
  536.     }
  537.     }
  538. }
  539.  
  540. /*
  541.  * Update the displayed status.  The current code in botl.c updates
  542.  * two lines of information.  Both lines are always updated one after
  543.  * the other.  So only do our update when we update the second line.
  544.  *
  545.  * Information on the first line:
  546.  *    name, attributes, alignment, score
  547.  *
  548.  * Information on the second line:
  549.  *     dlvl, gold, hp, power, ac, {level & exp or HD **}
  550.  *     status (hunger, conf, halu, stun, sick, blind), time, encumbrance
  551.  *
  552.  * [**] HD is shown instead of level and exp if POLYSELF is defined and
  553.  *    mtimedone is non-zero.
  554.  */
  555. static void
  556. update_fancy_status(wp)
  557.     struct xwindow *wp;
  558. {
  559.     const struct X_status_value *sv;
  560.     long val;
  561.     int i;
  562.  
  563.     if (wp->cursy != 0) return;    /* do a complete update when line 0 is done */
  564.  
  565. #ifdef GCC_WARN
  566.     val = 0;
  567. #endif
  568.  
  569.     for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) {
  570.     switch (i) {
  571.         case F_STR:        val = (long) ACURR(A_STR); break;
  572.         case F_DEX:        val = (long) ACURR(A_DEX); break;
  573.         case F_CON:        val = (long) ACURR(A_CON); break;
  574.         case F_INT:        val = (long) ACURR(A_INT); break;
  575.         case F_WIS:        val = (long) ACURR(A_WIS); break;
  576.         case F_CHA:        val = (long) ACURR(A_CHA); break;
  577.         /*
  578.          * Label stats.  With the exceptions of hunger and encumbrance,
  579.          * these are either on or off.  Pleae leave the ternary operators
  580.          * the way they are.  I want to specify 0 or 1, not a boolean.
  581.          */
  582.         case F_HUNGER:    val = (long) u.uhs;            break;
  583.         case F_CONFUSED:    val = (long) Confusion     ? 1L : 0L;    break;
  584.         case F_SICK:    val = (long) Sick       ? 1L : 0L;    break;
  585.         case F_BLIND:    val = (long) Blind       ? 1L : 0L;    break;
  586.         case F_STUNNED:    val = (long) Stunned       ? 1L : 0L;    break;
  587.         case F_HALLU:    val = (long) Hallucination ? 1L : 0L;    break;
  588.         case F_ENCUMBER:    val = (long) near_capacity();        break;
  589.  
  590.         case F_NAME:    val = (long) 0L; break;    /* special */
  591.         case F_DLEVEL:    val = (long) 0L; break;    /* special */
  592.         case F_GOLD:    val = (long) u.ugold; break;
  593. #ifdef POLYSELF
  594.         case F_HP:        val = (long) (u.mtimedone ?
  595.                           (u.mh  > 0 ? u.mh  : 0):
  596.                           (u.uhp > 0 ? u.uhp : 0)); break;
  597.         case F_MAXHP:    val = (long) (u.mtimedone ? u.mhmax :
  598.                                 u.uhpmax);  break;
  599. #else
  600.         case F_HP:        val = (long) (u.uhp > 0 ? u.uhp : 0);    break;
  601.         case F_MAXHP:    val = (long) u.uhpmax;    break;
  602. #endif
  603.         case F_POWER:    val = (long) u.uen;    break;
  604.         case F_MAXPOWER:    val = (long) u.uenmax;    break;
  605.         case F_AC:        val = (long) u.uac;    break;
  606. #ifdef POLYSELF
  607.         case F_LEVEL:    val = (long) (u.mtimedone ?
  608.                         mons[u.umonnum].mlevel :
  609.                         u.ulevel);        break;
  610. #else
  611.         case F_LEVEL:    val = (long) u.ulevel;    break;
  612. #endif
  613. #ifdef EXP_ON_BOTL
  614.         case F_EXP:        val = flags.showexp ? u.uexp : 0L; break;
  615. #else
  616.         case F_EXP:        val = 0L; break;
  617. #endif
  618.         case F_ALIGN:    val = (long) u.ualign.type; break;
  619.         case F_TIME:    val = flags.time ? (long) moves : 0L;    break;
  620. #ifdef SCORE_ON_BOTL
  621.         case F_SCORE:    val = flags.showscore ? botl_score():0L; break;
  622. #else
  623.         case F_SCORE:    val = 0L; break;
  624. #endif
  625.         default:
  626.         {
  627.         /*
  628.          * There is a possible infinite loop that occurs with:
  629.          *
  630.          *     impossible->pline->flush_screen->bot->bot{1,2}->
  631.          *     putstr->adjust_status->update_other->impossible
  632.          *
  633.          * Break out with this.
  634.          */
  635.         static boolean active = FALSE;
  636.         if (!active) {
  637.             active = TRUE;
  638.             impossible("update_other: unknown shown value");
  639.             active = FALSE;
  640.         }
  641.         break;
  642.         }
  643.     }
  644.     update_val(sv, val);
  645.     }
  646. }
  647.  
  648. /*
  649.  * Turn off hilighted status values after a certain amount of turns.
  650.  */
  651. void
  652. check_turn_events()
  653. {
  654.     int i;
  655.     struct X_status_value *sv;
  656.  
  657.     for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) {
  658.     if (!sv->set) continue;
  659.  
  660.     if (sv->turn_count++ >= hilight_time) {
  661.         if (sv->type == SV_LABEL)
  662.         hilight_label(sv->w);
  663.         else
  664.         hilight_value(sv->w);
  665.         sv->set = FALSE;
  666.     }
  667.     }
  668. }
  669.  
  670. /* Initialize alternate status ============================================= */
  671.  
  672. /* Return a string for the initial width. */
  673. static const char *
  674. width_string(sv_index)
  675.     int sv_index;
  676. {
  677.     switch (sv_index) {
  678.     case F_STR:    return "018/**";
  679.     case F_DEX:
  680.     case F_CON:
  681.     case F_INT:
  682.     case F_WIS:
  683.     case F_CHA:    return "088";    /* all but str never get bigger */
  684.  
  685.     case F_HUNGER:    return shown_stats[F_HUNGER].name;
  686.     case F_CONFUSED:return shown_stats[F_CONFUSED].name;
  687.     case F_SICK:    return shown_stats[F_SICK].name;
  688.     case F_BLIND:    return shown_stats[F_BLIND].name;
  689.     case F_STUNNED: return shown_stats[F_STUNNED].name;
  690.     case F_HALLU:    return shown_stats[F_HALLU].name;
  691.     case F_ENCUMBER:return shown_stats[F_ENCUMBER].name;
  692.  
  693.     case F_NAME:
  694.     case F_DLEVEL:    return "";
  695.     case F_HP:
  696.     case F_MAXHP:    return "9999";
  697.     case F_POWER:
  698.     case F_MAXPOWER:return "999";
  699.     case F_AC:    return "-99";
  700.     case F_LEVEL:    return "99";
  701.     case F_GOLD:
  702.     case F_EXP:    return "4294967295";    /* max ulong */
  703.     case F_ALIGN:    return "Neutral";
  704.     case F_TIME:    return "4294967295";    /* max ulong */
  705.     case F_SCORE:    return "4294967295";    /* max ulong */
  706.     }
  707.     impossible("width_string: unknown index %d\n", sv_index);
  708.     return "";
  709. }
  710.  
  711. static void
  712. create_widget(parent, sv, sv_index)
  713.     Widget parent;
  714.     struct X_status_value *sv;
  715.     int sv_index;
  716. {
  717.     Arg args[4];
  718.     Cardinal num_args;
  719.  
  720.     switch (sv->type) {
  721.     case SV_VALUE:
  722.         sv->w = create_value(parent, sv->name);
  723.         set_value(sv->w, width_string(sv_index));
  724.         break;
  725.     case SV_LABEL:
  726.         /* Labels get their own buffer. */
  727.         sv->name = (char *) alloc(BUFSZ);
  728.         sv->name[0] = '\0';
  729.  
  730.         num_args = 0;
  731.         XtSetArg(args[num_args], XtNborderWidth, 0);    num_args++;
  732.         XtSetArg(args[num_args], XtNinternalHeight, 0);    num_args++;
  733.         sv->w = XtCreateManagedWidget(
  734.                 sv_index == F_NAME ? "name" : "dlevel",
  735.                 labelWidgetClass,
  736.                 parent,
  737.                 args, num_args);
  738.         break;
  739.     case SV_NAME:
  740.         num_args = 0;
  741.         XtSetArg(args[num_args], XtNborderWidth, 0);    num_args++;
  742.         XtSetArg(args[num_args], XtNinternalHeight, 0);    num_args++;
  743.         sv->w = XtCreateManagedWidget(sv->name,
  744.                     labelWidgetClass,
  745.                     parent,
  746.                     args, num_args);
  747.         break;
  748.     default:
  749.         panic("create_widget: unknown type %d", sv->type);
  750.     }
  751. }
  752.  
  753. /*
  754.  * Get current width of value.  width2p is only valid for SV_LABEL types.
  755.  */
  756. static void
  757. get_widths(sv, width1p, width2p)
  758.     struct X_status_value *sv;
  759.     int *width1p, *width2p;
  760. {
  761.     Arg args[1];
  762.     Dimension width;
  763.  
  764.     switch (sv->type) {
  765.     case SV_VALUE:
  766.         *width1p = get_name_width(sv->w);
  767.         *width2p = get_value_width(sv->w);
  768.         break;
  769.     case SV_LABEL:
  770.     case SV_NAME:
  771.         XtSetArg(args[0], XtNwidth, &width);
  772.         XtGetValues(sv->w, args, ONE);
  773.         *width1p = width;
  774.         *width2p = 0;
  775.         break;
  776.     default:
  777.         panic("get_widths: unknown type %d", sv->type);
  778.     }
  779. }
  780.  
  781. static void
  782. set_widths(sv, width1, width2)
  783.     struct X_status_value *sv;
  784.     int width1, width2;
  785. {
  786.     Arg args[1];
  787.  
  788.     switch (sv->type) {
  789.     case SV_VALUE:
  790.         set_name_width(sv->w, width1);
  791.         set_value_width(sv->w, width2);
  792.         break;
  793.     case SV_LABEL:
  794.     case SV_NAME:
  795.         XtSetArg(args[0], XtNwidth, (width1+width2));
  796.         XtSetValues(sv->w, args, ONE);
  797.         break;
  798.     default:
  799.         panic("set_widths: unknown type %d", sv->type);
  800.     }
  801. }
  802.  
  803. static Widget
  804. init_column(name, parent, top, left, col_indices)
  805.     char *name;
  806.     Widget parent, top, left;
  807.     int *col_indices;
  808. {
  809.     Widget form;
  810.     Arg args[4];
  811.     Cardinal num_args;
  812.     int max_width1, width1, max_width2, width2;
  813.     int *ip;
  814.     struct X_status_value *sv;
  815.  
  816.     num_args = 0;
  817.     if (top != (Widget) 0) {
  818.     XtSetArg(args[num_args], XtNfromVert, top);        num_args++;
  819.     }
  820.     if (left != (Widget) 0) {
  821.     XtSetArg(args[num_args], XtNfromHoriz, left);    num_args++;
  822.     }
  823.     XtSetArg(args[num_args], XtNdefaultDistance, 0);    num_args++;
  824.     form = XtCreateManagedWidget(name,
  825.                 formWidgetClass,
  826.                 parent, args, num_args);
  827.  
  828.     max_width1 = max_width2 = 0;
  829.     for (ip = col_indices; *ip >= 0; ip++) {
  830.     sv = &shown_stats[*ip];
  831.     create_widget(form, sv, *ip);    /* will set init width */
  832.     if (ip != col_indices) {    /* not first */
  833.         num_args = 0;
  834.         XtSetArg(args[num_args], XtNfromVert, shown_stats[*(ip-1)].w);
  835.                                 num_args++;
  836.         XtSetValues(sv->w, args, num_args);
  837.     }
  838.     get_widths(sv, &width1, &width2);
  839.     if (width1 > max_width1) max_width1 = width1;
  840.     if (width2 > max_width2) max_width2 = width2;
  841.     }
  842.     for (ip = col_indices; *ip >= 0 ; ip++) {
  843.     set_widths(&shown_stats[*ip], max_width1, max_width2);
  844.     }
  845.  
  846.     /* There is room behind the end marker for the two widths. */
  847.     *++ip = max_width1;
  848.     *++ip = max_width2;
  849.  
  850.     return form;
  851. }
  852.  
  853. /*
  854.  * These are the orders of the displayed columns.  Change to suit.  The -1
  855.  * indicates the end of the column.  The two numbers after that are used
  856.  * to store widths that are calculated at run-time.
  857.  */
  858. static int attrib_indices[] = { F_STR,F_DEX,F_CON,F_INT,F_WIS,F_CHA, -1,0,0 };
  859. static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND,
  860.                 F_STUNNED, F_HALLU, F_ENCUMBER, -1,0,0 };
  861.  
  862. static int col2_indices[] = { F_MAXHP,    F_ALIGN, F_TIME, F_EXP,
  863.                   F_MAXPOWER, -1,0,0 };
  864. static int col1_indices[] = { F_HP,       F_AC,    F_GOLD, F_LEVEL,
  865.                   F_POWER,    F_SCORE, -1,0,0 };
  866.  
  867.  
  868. /*
  869.  * Produce a form that looks like the following:
  870.  *
  871.  *           name
  872.  *          dlevel
  873.  * col1_indices[0]    col2_indices[0]
  874.  * col1_indices[1]    col2_indices[1]
  875.  *    .            .
  876.  *    .            .
  877.  * col1_indices[n]    col2_indices[n]
  878.  */
  879. static Widget
  880. init_info_form(parent, top, left)
  881.     Widget parent, top, left;
  882. {
  883.     Widget form, col1;
  884.     struct X_status_value *sv_name, *sv_dlevel;
  885.     Arg args[6];
  886.     Cardinal num_args;
  887.     int total_width, *ip;
  888.  
  889.     num_args = 0;
  890.     if (top != (Widget) 0) {
  891.     XtSetArg(args[num_args], XtNfromVert, top);    num_args++;
  892.     }
  893.     if (left != (Widget) 0) {
  894.     XtSetArg(args[num_args], XtNfromHoriz, left);    num_args++;
  895.     }
  896.     XtSetArg(args[num_args], XtNdefaultDistance, 0);    num_args++;
  897.     form = XtCreateManagedWidget("status_info",
  898.                 formWidgetClass,
  899.                 parent,
  900.                 args, num_args);
  901.  
  902.     /* top of form */
  903.     sv_name = &shown_stats[F_NAME];
  904.     create_widget(form, sv_name, F_NAME);
  905.  
  906.     /* second */
  907.     sv_dlevel = &shown_stats[F_DLEVEL];
  908.     create_widget(form, sv_dlevel, F_DLEVEL);
  909.  
  910.     num_args = 0;
  911.     XtSetArg(args[num_args], XtNfromVert, sv_name->w);     num_args++;
  912.     XtSetValues(sv_dlevel->w, args, num_args);
  913.  
  914.     /* two columns beneath */
  915.     col1 = init_column("name_col1", form, sv_dlevel->w,
  916.                         (Widget) 0, col1_indices);
  917.     (void) init_column("name_col2", form, sv_dlevel->w,
  918.                               col1, col2_indices);
  919.  
  920.     /* Add calculated widths. */
  921.     for (ip = col1_indices; *ip >= 0; ip++)
  922.     ;    /* skip to end */
  923.     total_width = *++ip;
  924.     total_width += *++ip;
  925.     for (ip = col2_indices; *ip >= 0; ip++)
  926.     ;    /* skip to end */
  927.     total_width += *++ip;
  928.     total_width += *++ip;
  929.  
  930.     XtSetArg(args[0], XtNwidth, total_width);
  931.     XtSetValues(sv_name->w,   args, ONE);
  932.     XtSetArg(args[0], XtNwidth, total_width);
  933.     XtSetValues(sv_dlevel->w, args, ONE);
  934.  
  935.     return form;
  936. }
  937.  
  938. /*
  939.  * Create the layout for the fancy status.  Return a form widget that
  940.  * contains everything.
  941.  */
  942. static Widget
  943. create_fancy_status(parent, top)
  944.     Widget parent, top;
  945. {
  946.     Widget form;    /* The form that surrounds everything. */
  947.     Widget w;
  948.     Arg args[6];
  949.     Cardinal num_args;
  950.  
  951.     num_args = 0;
  952.     if (top != (Widget) 0) {
  953.     XtSetArg(args[num_args], XtNfromVert, top);    num_args++;
  954.     }
  955.     XtSetArg(args[num_args], XtNdefaultDistance, 0);    num_args++;
  956.     XtSetArg(args[num_args], XtNborderWidth, 0);    num_args++;
  957.     form = XtCreateManagedWidget("fancy_status",
  958.                 formWidgetClass,
  959.                 parent,
  960.                 args, num_args);
  961.  
  962.     w = init_info_form(form, (Widget) 0, (Widget) 0);
  963.     w =    init_column("status_attributes",form, (Widget) 0, w, attrib_indices);
  964.     (void) init_column("status_condition", form, (Widget) 0, w, status_indices);
  965.     return form;
  966. }
  967.  
  968.